import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Company } from "src/modules/company/company.entity";
import { Repository } from "typeorm";
import { CreateUserDto } from "./dto/create-user.dto";
import { UpdateUserDto } from "./dto/update-user.dto";
import { User } from "./user.entity";
import { ConfigService } from "nestjs-config";
import { createHmac } from "crypto";
import { CompanyService } from "src/modules/company/company.service";

const userSort = (users: User[]) => [
  ...users.filter((item) => item.role === "admin"),
  ...users
    .filter((item) => item.role === "manager")
    .sort((a, b) => b.date.getTime() - a.date.getTime()),
  ...users
    .filter((item) => !item.role)
    .sort((a, b) => b.date.getTime() - a.date.getTime()),
];

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
    private readonly config: ConfigService,
    private readonly companyService: CompanyService
  ) {}

  async create(
    createUserDto: CreateUserDto,
    company?: string | Company
  ): Promise<User> {
    const user = new User();
    Object.assign(user, createUserDto);
    if (!user.name) {
      user.name = user.username;
    }
    user.password = createHmac(
      "sha256",
      this.config.get("express.password") ?? "secret"
    )
      .update(user.password)
      .digest("hex");
    if (company) {
      user.company =
        company instanceof Company
          ? company
          : await this.companyService.find(company);
    }
    return this.userRepository.save(user);
  }

  async findAll(): Promise<User[]> {
    return userSort(await this.userRepository.find());
  }

  findByUsername(username: string): Promise<User | undefined> {
    return this.userRepository.findOne(
      {
        username,
      },
      { relations: ["company"] }
    );
  }

  async find(id: string): Promise<User> {
    return this.userRepository.findOneOrFail(id);
  }

  findOneWithCompany(id: string): Promise<User> {
    return this.userRepository.findOneOrFail(id, {
      relations: ["company"],
    });
  }

  async update(id: string, updateUserDto: UpdateUserDto): Promise<User> {
    const user = await this.find(id);
    Object.assign(user, updateUserDto);
    return this.userRepository.save(user);
  }

  async findByCompany(companyId: string) {
    return this.userRepository
      .createQueryBuilder("user")
      .innerJoinAndSelect(
        "user.company",
        "company",
        "company.id = :companyId",
        { companyId }
      )
      .getManyAndCount()
      .then((res) => {
        return [userSort(res[0]), res[1]];
      });
  }

  /**
   *
   * @param companyId 公司ID
   * @param page 页面
   * @param page_size 每页数量
   * @returns 公司指定页面的用户及总用户数量
   */
  async pageByCompany(companyId: string, page: number, page_size: number) {
    return this.userRepository
      .createQueryBuilder("user")
      .innerJoinAndSelect(
        "user.company",
        "company",
        "company.id = :companyId",
        { companyId }
      )
      .skip(page_size * (page - 1))
      .take(page_size)
      .getManyAndCount();
  }

  async remove(user: string | User) {
    const id = user instanceof User ? user.id : user;
    const userToRemove = await this.find(id);
    return await this.userRepository.remove(userToRemove);
  }
}
